package com.thiswhyme.storage.core;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import com.thiswhyme.common.expection.BusinessException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;

/**
 * @description: 文件存储服务
 * @author: thiswhyme
 * @date: 2021/9/18
 */
@Slf4j
@AllArgsConstructor
public class FileStorageService {

    private Map<String, FileStorage> fileStorageMap;

    /**
     * 获取对应的存储平台
     * @param platformCode 存储平台code
     * @return
     */
    public FileStorage getFileStorage(String platformCode) {
        return Optional.ofNullable(fileStorageMap.get(platformCode))
                .orElseThrow(() -> new BusinessException("存储平台不存在"));
    }

    /**
     * 文件上传
     * 简单文件上传, 最大支持 5 GB, 适用于小文件上传, 建议 20M以下的文件使用该接口
     * @param platformCode 存储平台Code
     * @param inputStream 文件输入流
     * @param keyName 文件名
     * @return 文件md5 //TODO
     */
    public String upload(String platformCode, InputStream inputStream, String keyName) {
        return getFileStorage(platformCode).upload(inputStream, keyName);
    }

    /**
     * 文件下载，输出到指定文件流消费者
     * @param platformCode 存储平台Code
     * @param keyName 文件唯一key
     * @param consumer 文件流消费者
     */
    public void download(String platformCode, String keyName, Consumer<InputStream> consumer) {
        getFileStorage(platformCode).download(keyName, consumer);
    }

    /**
     * 文件下载，输出到指定文件
     * @param platformCode 存储平台Code
     * @param keyName 文件唯一key
     * @param file 目标文件
     */
    public void download(String platformCode, String keyName, File file) {
        getFileStorage(platformCode).download(keyName, in -> {
            FileUtil.writeFromStream(in, file);
        });
    }

    /**
     * 文件下载，输出到指定OutputStream
     * @param platformCode 存储平台Code
     * @param keyName 文件唯一key
     * @param os 指定OutputStream
     */
    public void download(String platformCode, String keyName, OutputStream os) {
        getFileStorage(platformCode).download(keyName, in -> {
            IoUtil.copy(in, os);
            try {
                in.close();
            } catch (IOException e) {
                log.error("关闭流失败", e);
            }
        });
    }

    /**
     * 获取文件下载url
     * @param platformCode 存储平台Code
     * @param keyName 文件唯一key
     * @param expire 该url有效时间，公有bucket可不传该参数，私有bucket必传该参数（秒）
     * @return
     */
    public String fetchDownloadUrl(String platformCode, String keyName, Long expire) {
        return getFileStorage(platformCode).fetchDownloadUrl(keyName, expire);
    }

    /**
     * 批量删除文件
     * @param platformCode 存储平台Code
     * @param keyName 待删除的key
     */
    public void delete(String platformCode, String keyName) {
        if (StringUtils.hasText(keyName)) {
            batchDelete(platformCode, Collections.singletonList(keyName));
        }
    }

    /**
     * 批量删除文件
     * @param platformCode 存储平台Code
     * @param keyNames 待删除的key列表
     */
    public void batchDelete(String platformCode, List<String> keyNames) {
        getFileStorage(platformCode).batchDelete(keyNames);
    }
}
